package club.jdiy.admin.controller;

import club.jdiy.admin.SystemConfig;
import club.jdiy.admin.entity.Menu;
import club.jdiy.admin.interceptor.GuestDisabled;
import club.jdiy.admin.util.RSAUtils;
import club.jdiy.admin.entity.User;
import club.jdiy.admin.service.MenuService;
import club.jdiy.admin.service.UserService;
import club.jdiy.core.ex.JDiyException;
import club.jdiy.core.storage.Store;
import club.jdiy.dev.view.FtlInvoker;
import club.jdiy.dev.view.FtlParser;
import club.jdiy.utils.Md5Utils;
import club.jdiy.core.base.domain.Ret;
import club.jdiy.utils.StringUtils;
import freemarker.template.TemplateException;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.security.KeyPair;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.time.LocalDateTime;
import java.util.List;

@Controller
@RequestMapping("mgmt")
public class MainCtrl extends JDiyAdminCtrl<Menu, MenuService> {

    private void initMenus(List<Menu> menuList, FtlParser parser) {
        for (Menu m : menuList) {
            parser.addVariable("vo", m);
            if (StringUtils.hasText(m.getPageParam())) {
                try {
                    m.setPageParam_(parser.parse(m.getPageParam()));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if (m.getChildren() != null) initMenus(m.getChildren(), parser);
        }
    }

    @RequestMapping({"", "/"})
    public String main(ModelMap map) {


        List<Menu> menuList = service.findRootList();

        FtlParser parser = ftlInvoker.getParser();
        initMenus(menuList, parser);

        map.put("menuList", menuList);

        User user = context.getCurrentUser();
        map.put("CURRENT_USER", user);

        Store store = context.getStore("user", user.getId().toString());
        map.put("store", store);

        String userModel = user.getClass().getSimpleName();
        userModel = userModel.substring(0, 1).toLowerCase() + userModel.substring(1);
        map.put("userModel", userModel);
        map.put("isDeveloper", context.isDeveloper());
        map.put("jdiy", context.getConfig(SystemConfig.class));
        return "mgmt/main.ftl";
    }

    @RequestMapping(value = "login", method = RequestMethod.GET)
    public String login(String s, ModelMap map, HttpServletRequest request) throws Exception {
        if ("logout".equals(s)) context.setCookie("userId", null);
        KeyPair keyPair = RSAUtils.createKeyPair();
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        request.getSession().setAttribute("loginRSA-privateKey", privateKey);
        map.put("modulus", publicKey.getModulus().toString(16));
        map.put("exponent", publicKey.getPublicExponent().toString(16));


        map.put("yzmKey", yzmKey);
        map.put("s", s);
        map.put("jdiy", context.getConfig(SystemConfig.class));
        map.put("systemStore", context.getStore("system", "jdiy"));
        return "mgmt/login.ftl";
    }


    @RequestMapping(value = "login", method = RequestMethod.POST)
    @ResponseBody
    public Ret<String> login(String uid, String pwd, String yzm, String s,
                             HttpServletRequest request) {
        if ("logout".equals(s)) {
            context.setCookie("userId", null);
            return Ret.success();
        } else {
            RSAPrivateKey pk = (RSAPrivateKey) request.getSession().getAttribute("loginRSA-privateKey");
            if (pk == null) {
                return Ret.fail("会话过期，请刷新当前页面后再尝试登录!");
            }

            pwd = RSAUtils.decrypt(pwd, pk);
            String sYzm = (String) request.getSession().getAttribute(yzmKey);
            if ((yzm == null || !yzm.equalsIgnoreCase(sYzm)) && context.getConfig(SystemConfig.class).isYzmOn()) {
                return Ret.fail("验证码不正确!\r\n若看不清，可点击后面的图片换一张．");
            } else if (uid == null || "".equals(uid)) {
                return Ret.fail("用户名不能为空!");
            } else if ("".equals(pwd)) {
                return Ret.fail("密码不能为空!");
            } else {
                request.getSession().removeAttribute(yzmKey);

                User user = userService.findUser(uid);


                if (user == null || !Md5Utils.validate(pwd, user.getPwd())) {
                    return new Ret<>(Ret.RetCode.fail.getCode(), "用户名或密码错误，登录失败!", "refreshYzm");
                } else {
                    if (user.getRoleList() == null || user.getRoleList().size() < 1)
                        return new Ret<>(Ret.RetCode.fail.getCode(), "当前用户未授予后台操作权限，无法登录!", "refreshYzm");
                    context.setCookie("userId", user.getId().toString());
                    user.setLoginDt(LocalDateTime.now());
                    user.setLoginIp(context.getIp());
                    request.setAttribute("CURRENT_USER", user = userService.save(user));

                    context.setCookie("userToken", user.token(context.getConfig(SystemConfig.class).isSingleLoginOn()));

                    return Ret.success();
                }
            }
        }
    }

    @RequestMapping("main/{page}")
    public String mainPages(@PathVariable String page, ModelMap map) {
        Store store = context.getStore("user", context.getCurrentUser().getId().toString());
        map.put("store", store);
        map.put("jdiy", context.getConfig(SystemConfig.class));
        return "mgmt/" + page + ".ftl";
    }


    @RequestMapping("main/updateProfile")
    @ResponseBody
    @GuestDisabled
    public Ret<?> updateProfile(User vo, MultipartFile avatar) throws IOException {
        try {
            User currentUser = context.getCurrentUser();
            Store store = context.getStore("user", currentUser.getId().toString());
            store.set("avatar", avatar);

            vo.setId(currentUser.getId());
            userService.updateProfile(vo);

            return Ret.success();
        } catch (JDiyException le) {
            return Ret.error(le);
        }
    }

    @RequestMapping("main/changePwd")
    @ResponseBody
    @GuestDisabled
    public Ret<?> changePwd(String oldPwd, String newPwd) {
        try {
            if (newPwd == null || newPwd.length() < 6) throw new JDiyException("新密码长度不得小于6个字符。");

            User user = userService.changePwd(
                    context.getCurrentUser().getId(),
                    oldPwd,
                    newPwd
            );
            context.setCookie("userToken", user.token(context.getConfig(SystemConfig.class).isSingleLoginOn()));
            return Ret.success();
        } catch (JDiyException le) {
            return Ret.error(le);
        }
    }


    private static final String yzmKey = "admLogin_yzm";
    @Resource
    private UserService userService;

    @Resource
    private FtlInvoker ftlInvoker;
}
